/**
 * WebSocket 通知推送服务
 * 负责建立WebSocket连接、订阅通知、处理消息推送
 */

import SockJS from "sockjs-client";
import { Client, type IMessage } from "@stomp/stompjs";
import type { NotificationDetail, UnreadCount } from "@/api/notification";

/** WebSocket配置 */
interface WebSocketConfig {
  /** WebSocket服务器基础URL */
  baseUrl: string;
  /** 是否开启调试日志 */
  debug?: boolean;
  /** 自动重连延迟（毫秒） */
  reconnectDelay?: number;
  /** 心跳间隔（毫秒） */
  heartbeatInterval?: number;
  /** 最大重连次数 */
  maxReconnectAttempts?: number;
}

/** 回调函数类型 */
interface WebSocketCallbacks {
  /** 收到新通知的回调 */
  onNotification?: (notification: NotificationDetail) => void;
  /** 未读数量更新的回调 */
  onUnreadCount?: (unreadCount: UnreadCount) => void;
  /** 连接成功的回调 */
  onConnect?: () => void;
  /** 连接失败的回调 */
  onError?: (error: any) => void;
  /** 连接关闭的回调 */
  onClose?: () => void;
}

/**
 * WebSocket通知服务类
 */
class NotificationWebSocketService {
  /** STOMP客户端 */
  private client: Client | null = null;
  /** 连接状态 */
  private connected = false;
  /** 重连次数 */
  private reconnectAttempts = 0;
  /** 配置 */
  private config: Required<WebSocketConfig>;
  /** 回调函数 */
  private callbacks: WebSocketCallbacks = {};
  /** 当前token */
  private currentToken: string | null = null;
  /** 订阅引用 - 用于取消订阅 */
  private subscriptions: Array<{ unsubscribe: () => void }> = [];

  constructor() {
    // 默认配置
    this.config = {
      baseUrl: import.meta.env.VITE_WS_URL || "http://localhost:8081",
      debug: import.meta.env.DEV,
      reconnectDelay: 3000, // 减少重连延迟到3秒
      heartbeatInterval: 10000, // 心跳增加到10秒(更符合标准)
      maxReconnectAttempts: 5
    };
  }

  /**
   * 连接WebSocket
   * @param token 用户认证token
   * @param callbacks 回调函数
   */
  connect(token: string, callbacks: WebSocketCallbacks = {}) {
    if (!token) {
      console.error("❌ Token不能为空，无法连接WebSocket");
      callbacks.onError?.(new Error("Token不能为空"));
      return;
    }

    // 如果已经连接，先断开旧连接
    if (this.client && this.connected) {
      console.log("🔄 检测到已有连接，先断开旧连接...");
      this.disconnect();
    }

    this.currentToken = token;
    this.callbacks = callbacks;

    // 构建WebSocket URL（在URL参数中传递token）
    const wsUrl = `${this.config.baseUrl}/ws/notifications?token=${token}`;

    if (this.config.debug) {
      console.log("🔌 正在连接WebSocket:", wsUrl);
    }

    // 创建SockJS连接
    const socket = new SockJS(wsUrl);

    // 创建STOMP客户端
    this.client = new Client({
      webSocketFactory: () => socket,

      // 自动重连配置
      reconnectDelay: this.config.reconnectDelay,
      heartbeatIncoming: this.config.heartbeatInterval,
      heartbeatOutgoing: this.config.heartbeatInterval,

      // 禁用自动重连(我们手动控制)
      // reconnectDelay: 0, // 如果需要完全手动控制重连

      // 备用：STOMP头传递token
      connectHeaders: {
        Authorization: `Bearer ${token}`
      },

      // 优化配置：立即发送消息
      splitLargeFrames: false, // 不分割大帧,减少延迟
      forceBinaryWSFrames: false, // 使用文本帧(更快)

      // 连接成功回调
      onConnect: () => {
        if (this.config.debug) {
          console.log("✅ WebSocket连接成功");
        }

        this.connected = true;
        this.reconnectAttempts = 0;
        this.callbacks.onConnect?.();

        // 订阅个人通知
        this.subscribeNotifications();

        // 订阅未读数量
        this.subscribeUnreadCount();

        // 订阅系统广播（可选）
        this.subscribeBroadcast();
      },

      // STOMP错误回调
      onStompError: frame => {
        console.error("❌ STOMP错误:", frame);
        this.connected = false;

        // 可能是token过期或无效
        if (frame.headers?.message) {
          console.error("错误信息:", frame.headers.message);

          // 提示用户重新登录
          if (
            frame.headers.message.includes("token") ||
            frame.headers.message.includes("unauthorized")
          ) {
            this.handleAuthError();
          }
        }

        this.callbacks.onError?.(frame);
      },

      // WebSocket错误回调
      onWebSocketError: error => {
        console.error("❌ WebSocket连接错误:", error);
        this.connected = false;
        this.callbacks.onError?.(error);
      },

      // WebSocket关闭回调
      onWebSocketClose: event => {
        if (this.config.debug) {
          console.log("🔌 WebSocket连接关闭", event);
        }

        this.connected = false;
        this.callbacks.onClose?.();

        // 尝试重连
        this.handleReconnect();
      },

      // 调试日志
      debug: this.config.debug
        ? (str: string) => {
            console.log("STOMP:", str);
          }
        : undefined
    });

    // 激活连接
    this.client.activate();
  }

  /**
   * 订阅个人通知
   */
  private subscribeNotifications() {
    if (!this.client) return;

    const subscription = this.client.subscribe(
      "/user/queue/notifications",
      (message: IMessage) => {
        try {
          const receiveTime = Date.now();
          const notification: NotificationDetail = JSON.parse(message.body);

          if (this.config.debug) {
            // 计算延迟(如果后端返回发送时间)
            const sendTime = (notification as any).timestamp
              ? new Date((notification as any).timestamp).getTime()
              : null;
            const delay = sendTime ? receiveTime - sendTime : null;
            console.log(
              "📨 收到新通知:",
              notification,
              delay ? `延迟: ${delay}ms` : ""
            );
          }

          // 立即触发回调,不做任何延迟处理
          this.callbacks.onNotification?.(notification);
        } catch (error) {
          console.error("❌ 解析通知消息失败:", error);
        }
      }
    );

    // 保存订阅引用
    this.subscriptions.push(subscription);
  }

  /**
   * 订阅未读数量
   */
  private subscribeUnreadCount() {
    if (!this.client) return;

    const subscription = this.client.subscribe(
      "/user/queue/unread-count",
      (message: IMessage) => {
        try {
          const data: UnreadCount = JSON.parse(message.body);

          if (this.config.debug) {
            console.log("🔔 未读数量更新:", data);
          }

          this.callbacks.onUnreadCount?.(data);
        } catch (error) {
          console.error("❌ 解析未读数量消息失败:", error);
        }
      }
    );

    // 保存订阅引用
    this.subscriptions.push(subscription);
  }

  /**
   * 订阅系统广播
   */
  private subscribeBroadcast() {
    if (!this.client) return;

    const subscription = this.client.subscribe(
      "/topic/notifications",
      (message: IMessage) => {
        try {
          const notification: NotificationDetail = JSON.parse(message.body);

          if (this.config.debug) {
            console.log("📢 收到系统广播:", notification);
          }

          this.callbacks.onNotification?.(notification);
        } catch (error) {
          console.error("❌ 解析广播消息失败:", error);
        }
      }
    );

    // 保存订阅引用
    this.subscriptions.push(subscription);
  }

  /**
   * 处理认证错误
   */
  private handleAuthError() {
    console.error("❌ WebSocket认证失败，请重新登录");

    // 触发全局事件
    window.dispatchEvent(new CustomEvent("websocket-auth-error"));
  }

  /**
   * 处理重连
   */
  private handleReconnect() {
    // 检查token是否还有效（避免使用已失效的token重连）
    if (!this.currentToken) {
      console.warn("⚠️ Token已清除，停止重连");
      return;
    }

    if (this.reconnectAttempts < this.config.maxReconnectAttempts) {
      this.reconnectAttempts++;

      if (this.config.debug) {
        console.log(
          `🔄 尝试重连 (${this.reconnectAttempts}/${this.config.maxReconnectAttempts})...`
        );
      }

      setTimeout(() => {
        // 再次检查token（防止在延迟期间用户登出）
        if (this.currentToken) {
          this.connect(this.currentToken, this.callbacks);
        } else {
          console.warn("⚠️ Token在重连等待期间被清除，取消重连");
        }
      }, this.config.reconnectDelay);
    } else {
      console.error("❌ 达到最大重连次数，停止重连");
    }
  }

  /**
   * 断开连接
   */
  disconnect() {
    if (this.client) {
      if (this.config.debug) {
        console.log("🔌 断开WebSocket连接");
      }

      // 取消所有订阅
      this.unsubscribeAll();

      // 断开STOMP连接
      this.client.deactivate();
      this.client = null;

      // 清理状态
      this.connected = false;
      this.reconnectAttempts = 0;
      this.currentToken = null;
      this.callbacks = {};
    }
  }

  /**
   * 取消所有订阅
   */
  private unsubscribeAll() {
    if (this.subscriptions.length > 0) {
      if (this.config.debug) {
        console.log(`📤 取消 ${this.subscriptions.length} 个订阅`);
      }

      this.subscriptions.forEach(subscription => {
        try {
          subscription.unsubscribe();
        } catch (error) {
          console.error("❌ 取消订阅失败:", error);
        }
      });

      this.subscriptions = [];
    }
  }

  /**
   * 检查连接状态
   */
  isConnected(): boolean {
    return this.connected;
  }

  /**
   * 更新配置
   */
  updateConfig(config: Partial<WebSocketConfig>) {
    this.config = { ...this.config, ...config };
  }
}

// 导出单例
export default new NotificationWebSocketService();
